package com.redlight.pool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by chao on 2019/1/23.
 */
public class ThreadPool {
    private Logger logger= LoggerFactory.getLogger(getClass());
    private ThreadPoolExecutor executor=null;//线程池对象
    private List<IPoolTask> taskList=null;//任务项
    private long tmout=5*60*100;//默认超时时间
    private Boolean isStop=false;//是否挺会
    private String poolId="";//线程池id
    private int coreTNum=5;//核心线程数
    private int maxTNum=5;//最大线程数
    private long keepAlive=10000L;
    private int cacheNum=30;
    private ThreadPoolMonitor monitor;
    public ThreadPool(){

    }
    public void init(PoolArgs nArgs)throws Exception{
        if(nArgs==null){
            throw new Exception("线程池参数不能为空");
        }
        if(nArgs.getId()==null || "".equals(nArgs.getId()))
            throw new Exception("线程id不能为空");
        logger.info("启动线程池"+nArgs.getId());
        this.coreTNum=(nArgs.getCoreTNum()==0?this.coreTNum :nArgs.getCoreTNum());
        this.maxTNum=(nArgs.getMaxTNum()==0?this.maxTNum :nArgs.getMaxTNum());
        this.cacheNum=(nArgs.getCacheTNum()==0?this.cacheNum :nArgs.getCacheTNum());
        this.keepAlive=(nArgs.getKeepAlive()==0?this.keepAlive :nArgs.getKeepAlive());
        executor=new ThreadPoolExecutor(coreTNum,maxTNum,keepAlive, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(cacheNum),new ThreadPoolExecutor.CallerRunsPolicy());
        monitor=new ThreadPoolMonitor(this);
        taskList=new Vector<IPoolTask>();
        logger.info("线程池启动完成"+poolId);

    }

    /**
     *
     * 提交任务带监控时间
     * @param task
     */
    public void excute(IPoolRunnableTask task){
        synchronized (taskList){
            if(executor!=null)
                executor.execute(task);
            if(taskList!=null)
                taskList.add(task);
        }
    }

    /**
     * 提交任务不带监控时间
     * @param task
     */
    public void setWithoutTmout(IPoolRunnableTask task){
        synchronized (taskList){
            if(executor!=null)
                executor.execute(task);
        }
    }

    /**
     * 提交任务
     * @param task
     * @return
     */
    public Future submit(IPoolRunnableTask task){
        synchronized (taskList){
            if(executor!=null){
                Future f=executor.submit(task);
                taskList.add(task);
                return f;
            }
            return null;
        }
    }

    /**
     * 提交任务
     * @param task
     * @return
     */
    public Future submit(IPoolCallableTask task){
        synchronized (taskList){
            if(executor!=null){
                return null;
            }
            Future result=executor.submit(task);
            return result;
        }
    }

    /**
     * 移除任务
     * @param task
     */
    public void  removeTask(IPoolTask task){
        synchronized (taskList){
            if(taskList!=null){
                taskList.remove(task);
            }
        }
    }

    public void stop(){
        if(!isStop){
            if(monitor!=null)
                monitor.stop();
            if(executor!=null){
                executor.shutdown();
                taskList=null;
                isStop=true;
            }
        }
    }

    /**
     * 获取任务项
     * @return
     */
    public List<IPoolTask> getTasks(){
        return  taskList;
    }
    public long getTmout(){
        return tmout;
    }
    public ThreadPoolExecutor getPool(){
        return executor;
    }
    public String getPoolId(){
        return poolId;
    }
    public void setPoolId(String poolId){
        this.poolId=poolId;
    }

    /**
     * 线程池检测工具
     */
    public class ThreadPoolMonitor implements  Runnable{
        private ThreadPool pool=null;
        private  boolean runFlg=false;
        private long sleepTm=60*2*1000;


        public  ThreadPoolMonitor (ThreadPool pool){
            this.pool=pool;
        }

        /**
         * 启动监控器
         */
        public void start() {
            if(!runFlg){
                logger.info("开始启动线程池"+poolId+"的监控器");
                this.runFlg=true;
                Thread t=new Thread(this);
                t.start();
                logger.info("线程池"+poolId+"的监控器启动完成");
            }
        }

        /**
         * 关闭监控器
         */
        public void stop(){
            this.runFlg=false;
        }

        @Override
        public void run() {
            while (runFlg){
                try {
                    if(pool==null)
                        runFlg=false;
                    //获取所有任务
                    List<IPoolTask> tasks=pool.getTasks();
                    //待关闭的任务
                    List<IPoolTask> removeList=new ArrayList<>();
                    synchronized (tasks){
                        if(tasks!=null && tasks.size()>0){
                            for(IPoolTask task :tasks){
                                if(!task.getRunnFlg()){
                                    removeList.add(task);
                                    continue;
                                }

                                //超时时间
                                long tmout=pool.getTmout();
                                //任务开始时间
                                long startTim=task.getStartTim();
                                //系统当前时间
                                long curTim=System.currentTimeMillis();

                                //启动时长
                                long t=curTim-startTim;
                                if(t>tmout)
                                    removeList.add(task);
                                else
                                    continue;
                                for(IPoolTask rmTask :removeList){
                                    Thread taskT=rmTask.getThread();
                                    if(!task.getRunnFlg()){
                                        removeList.remove(rmTask);
                                        continue;
                                    }
                                    if(taskT!=null && taskT.isAlive()){
                                        try {
                                        logger.info("线程"+rmTask.getThreadId()+"超时，尝试关闭");
                                        removeList.remove(rmTask);
                                        logger.info("超时已经关闭");
                                        }catch (Throwable e){

                                        }

                                    }
                                }
                            }
                        }
                    }
                    Thread.sleep(sleepTm);

                }catch (Exception e){
                    logger.error("检测超时任务失败",e);
                }
            }
        }
    }
}
